﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ChartDirector;

namespace GoodTrader.GTChart
{
    public partial class frmOptChart : Form
    {
        private GTDownload.CpDataSet mCpDataSetObj = null;
        public GTDownload.CpDataSet CpDataSetObj
        {
            get { return mCpDataSetObj; }
            set { mCpDataSetObj = value; }
        }

        public frmOptChart()
        {
            InitializeComponent();
        }

        private class ListItem
        {
            string m_key;
            string m_value;

            public ListItem(string key, string val)
            {
                m_key = key;
                m_value = val;
            }

            public string Key
            {
                get { return m_key; }
            }

            public override string ToString()
            {
                return m_value;
            }
        }

        // The ticker symbol, timeStamps, volume, high, low, open and close data    
        string tickerKey = "";
      
        // An extra data series to compare with the close data
        private string compareKey = "";
        private double[] compareData = null;

        // Will set to true at the end of initialization - prevents events from firing before the
        // controls are properly initialized.
        private bool hasFinishedInitialization = false;

        /// <summary>
        /// Form Load event handler - initialize the form
        /// </summary>
        private void frmSystemChart_Load(object sender, System.EventArgs e)
        {
            hasFinishedInitialization = false;

            timeRange.Items.Add(new ListItem("1", "1 day"));
            timeRange.Items.Add(new ListItem("2", "2 days"));
            timeRange.Items.Add(new ListItem("5", "5 days"));
            timeRange.Items.Add(new ListItem("10", "10 days"));
            timeRange.Items.Add(new ListItem("30", "1 month"));
            timeRange.Items.Add(new ListItem("60", "2 months"));
            timeRange.Items.Add(new ListItem("90", "3 months"));
            timeRange.SelectedIndex = timeRange.Items.Add(new ListItem("180", "6 months"));
            timeRange.Items.Add(new ListItem("360", "1 year"));
            timeRange.Items.Add(new ListItem("720", "2 years"));
            timeRange.Items.Add(new ListItem("1080", "3 years"));
            timeRange.Items.Add(new ListItem("1440", "4 years"));
            timeRange.Items.Add(new ListItem("1800", "5 years"));
            timeRange.Items.Add(new ListItem("3600", "10 years"));

            chartSize.Items.Add(new ListItem("S", "Small"));
            chartSize.Items.Add(new ListItem("M", "Medium"));
            chartSize.Items.Add(new ListItem("H", "Huge"));
            chartSize.Items.Add(new ListItem("E", "Entire"));
            chartSize.SelectedIndex = chartSize.Items.Add(new ListItem("E", "Entire"));


            chartType.Items.Add(new ListItem("None", "None"));
            chartType.SelectedIndex = chartType.Items.Add(new ListItem("CandleStick", "CandleStick"));
            chartType.Items.Add(new ListItem("Close", "Closing Price"));
            chartType.Items.Add(new ListItem("Median", "Median Price"));
            chartType.Items.Add(new ListItem("OHLC", "OHLC"));
            chartType.Items.Add(new ListItem("TP", "Typical Price"));
            chartType.Items.Add(new ListItem("WC", "Weighted Close"));

            priceBand.Items.Add(new ListItem("None", "None"));
            priceBand.SelectedIndex = priceBand.Items.Add(new ListItem("BB", "Bollinger Band"));
            priceBand.Items.Add(new ListItem("DC", "Donchain Channel"));
            priceBand.Items.Add(new ListItem("Envelop", "Envelop (SMA 20 +/- 10%)"));

            avgType1.Items.Add(new ListItem("None", "None"));
            avgType1.SelectedIndex = avgType1.Items.Add(new ListItem("SMA", "Simple"));
            avgType1.Items.Add(new ListItem("EMA", "Exponential"));
            avgType1.Items.Add(new ListItem("TMA", "Triangular"));
            avgType1.Items.Add(new ListItem("WMA", "Weighted"));

            avgType2.Items.Add(new ListItem("None", "None"));
            avgType2.SelectedIndex = avgType2.Items.Add(new ListItem("SMA", "Simple"));
            avgType2.Items.Add(new ListItem("EMA", "Exponential"));
            avgType2.Items.Add(new ListItem("TMA", "Triangular"));
            avgType2.Items.Add(new ListItem("WMA", "Weighted"));

            ListItem[] indicators = 
			{
				new ListItem("None", "None"),
				new ListItem("AccDist", "Accumulation/Distribution"),
				new ListItem("AroonOsc", "Aroon Oscillator"),
				new ListItem("Aroon", "Aroon Up/Down"),
				new ListItem("ADX", "Avg Directional Index"),
				new ListItem("ATR", "Avg True Range"),
				new ListItem("BBW", "Bollinger Band Width"),
				new ListItem("CMF", "Chaikin Money Flow"),
				new ListItem("COscillator", "Chaikin Oscillator"),
				new ListItem("CVolatility", "Chaikin Volatility"),
				new ListItem("CLV", "Close Location Value"),
				new ListItem("CCI", "Commodity Channel Index"),
				new ListItem("DPO", "Detrended Price Osc"),
				new ListItem("DCW", "Donchian Channel Width"),
				new ListItem("EMV", "Ease of Movement"),
				new ListItem("FStoch", "Fast Stochastic"),
				new ListItem("MACD", "MACD"),
				new ListItem("MDX", "Mass Index"),
				new ListItem("Momentum", "Momentum"),
				new ListItem("MFI", "Money Flow Index"),
				new ListItem("NVI", "Neg Volume Index"),
				new ListItem("OBV", "On Balance Volume"),
				new ListItem("Performance", "Performance"),
				new ListItem("PPO", "% Price Oscillator"),
				new ListItem("PVO", "% Volume Oscillator"),
				new ListItem("PVI", "Pos Volume Index"),
				new ListItem("PVT", "Price Volume Trend"),
				new ListItem("ROC", "Rate of Change"),
				new ListItem("RSI", "RSI"),
				new ListItem("SStoch", "Slow Stochastic"),
				new ListItem("StochRSI", "StochRSI"),
				new ListItem("TRIX", "TRIX"),
				new ListItem("UO", "Ultimate Oscillator"),
				new ListItem("Vol", "Volume"),
				new ListItem("WilliamR", "William's %R")
			};

            indicator1.Items.AddRange(indicators);
            indicator2.Items.AddRange(indicators);
            indicator3.Items.AddRange(indicators);
            indicator4.Items.AddRange(indicators);

            for (int i = 0; i < indicators.Length; ++i)
            {
                if (indicators[i].Key == "RSI")
                    indicator1.SelectedIndex = i;
                else if (indicators[i].Key == "MACD")
                    indicator2.SelectedIndex = i;
            }
            indicator3.SelectedIndex = 0;
            indicator4.SelectedIndex = 0;

            hasFinishedInitialization = true;
            //drawChart(winChartViewer1);
            InitTimer();
        }

       
        /// <summary>
        /// In this sample code, the chart updates when the user selection changes. You may 
        /// modify the code to update the data and chart periodically for real time charts.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void selectionChanged(object sender, System.EventArgs e)
        {
            if (hasFinishedInitialization)
                drawChart(optChartViewer);
        }

        ///
        /// For the ticker symbols, the chart will update when the user enters a new symbol,
        /// and then press the enter button or leave the text box.
        ///

        private void tickerSymbol_Leave(object sender, System.EventArgs e)
        {
            // User leave ticker symbol text box - redraw chart if symbol has changed
            if (tickerSymbol.Text != tickerKey)
                drawChart(optChartViewer);
        }

        private void tickerSymbol_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            // User press enter key - same action as leaving the text box.
            if (e.KeyChar == '\r')
                tickerSymbol_Leave(sender, e);
        }

        private void compareWith_Leave(object sender, System.EventArgs e)
        {
            // User leave compare symbol text box - redraw chart if symbol has changed
            if (compareWith.Text != compareKey)
                drawChart(optChartViewer);
        }

        private void compareWith_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            // User press enter key - same action as leaving the text box.
            if (e.KeyChar == '\r')
                compareWith_Leave(sender, e);
        }

        /// <summary>
        /// Draw the chart according to user selection and display it in the WinChartViewer.
        /// </summary>
        /// <param name="viewer">The WinChartViewer object to display the chart.</param>
        private void drawChart(WinChartViewer viewer)
        {
         

            int avgPeriod1;
            try { avgPeriod1 = int.Parse(movAvg1.Text); }
            catch { avgPeriod1 = 0; }
            avgPeriod1 = Math.Max(0, Math.Min(300, avgPeriod1));

            // The second moving average period selected by the user.
            int avgPeriod2;
            try { avgPeriod2 = int.Parse(movAvg2.Text); }
            catch { avgPeriod2 = 0; }
            avgPeriod2 = Math.Max(0, Math.Min(300, avgPeriod2));

            // We need extra leading data points in order to compute moving averages.
            int extraPoints = Math.Max(20, Math.Max(avgPeriod1, avgPeriod2));

            //
            // At this stage, all data is available. We can draw the chart as according to 
            // user input.
            //

            //
            // Determine the chart size. In this demo, user can select 4 different chart
            // sizes. Default is the large chart size.
            //
            int width = 780;
            int mainHeight = 255;
            int indicatorHeight = 80;
            int totalHeight = 0;

            string selectedSize = ((ListItem)chartSize.SelectedItem).Key;
            if (selectedSize == "S")
            {
                // Small chart size
                width = 450;
                mainHeight = 160;
                indicatorHeight = 60;
            }
            else if (selectedSize == "M")
            {
                // Medium chart size
                width = 620;
                mainHeight = 215;
                indicatorHeight = 70;
            }
            else if (selectedSize == "H")
            {
                // Huge chart size
                width = 1000;
                mainHeight = 320;
                indicatorHeight = 90;
            }
            else if (selectedSize == "E")
            {
                // Huge chart size
                width = rightPanel.Width - 50;
                mainHeight = rightPanel.Height - 280;
                indicatorHeight = 90;
            }

            // Create the chart object using the selected size
            FinanceChart m = new FinanceChart(width);



            // Set the data into the chart object
            //m.setData(timeStamps, highData, lowData, openData, closeData, volData, extraPoints);
            GTGlobal.StockTimeToChartDirectorTime(mCpDataSetObj.OptionDataList[0].Date, mCpDataSetObj.OptionDataList[0].Time, mCpDataSetObj.OptionDataList[0].cTime);

            m.setData(mCpDataSetObj.OptionDataList[0].cTime, mCpDataSetObj.OptionDataList[0].High, mCpDataSetObj.OptionDataList[0].Low, mCpDataSetObj.OptionDataList[0].Open, mCpDataSetObj.OptionDataList[0].Close, mCpDataSetObj.OptionDataList[0].Amount, extraPoints);


            //
            // We configure the title of the chart. In this demo chart design, we put the 
            // company name as the top line of the title with left alignment.
            //
            m.addPlotAreaTitle(Chart.TopLeft, tickerKey);

         
            // A copyright message at the bottom left corner the title area
            m.addPlotAreaTitle(Chart.BottomRight,
                "<*font=arial.ttf,size=8*>Good Trader Engineering");

        
            XYChart mainChart = m.addMainChart(mainHeight);

            double hMin = 0.0, hMax = 0.0;
            GTGlobal.FindMinMax(mCpDataSetObj.OptionDataList[0].High, ref hMin, ref hMax);
            double lMin = 0.0, lMax = 0.0;
            GTGlobal.FindMinMax(mCpDataSetObj.OptionDataList[0].Low, ref lMin, ref lMax);
            double tMin = Math.Min(hMin, lMin);
            double tMax = Math.Max(hMax, lMax);

            mainChart.yAxis().setLinearScale(tMin, tMax, 1.0, 0.05);

            //
            // Set log or linear scale according to user preference
            //
            m.setLogScale(logScale.Checked);

            //
            // Set axis labels to show data values or percentage change to user preference
            //
            if (percentageScale.Checked)
                m.setPercentageAxis();

            //
            // Draw any price line the user has selected
            //
            string mainType = ((ListItem)chartType.SelectedItem).Key;
            if (mainType == "Close")
                m.addCloseLine(0x000040);
            else if (mainType == "TP")
                m.addTypicalPrice(0x000040);
            else if (mainType == "WC")
                m.addWeightedClose(0x000040);
            else if (mainType == "Median")
                m.addMedianPrice(0x000040);

            //
            // Add comparison line if there is data for comparison
            //
            if ((compareData != null) && (compareData.Length > extraPoints))
                m.addComparison(compareData, 0x0000ff, compareKey);

            //
            // Add moving average lines.
            //
            addMovingAvg(m, ((ListItem)avgType1.SelectedItem).Key, avgPeriod1, 0x663300);
            addMovingAvg(m, ((ListItem)avgType2.SelectedItem).Key, avgPeriod2, 0x9900ff);

            //
            // Draw candlesticks or OHLC symbols if the user has selected them.
            //
            if (mainType == "CandleStick")
                m.addCandleStick(0xff3333, 0x33ff33);
            else if (mainType == "OHLC")
                m.addHLOC(0x008800, 0xcc0000);

            //
            // Add parabolic SAR if necessary
            //
            if (parabolicSAR.Checked)
                m.addParabolicSAR(0.02, 0.02, 0.2, Chart.DiamondShape, 5, 0x008800, 0x000000);

            //
            // Add price band/channel/envelop to the chart according to user selection
            //
            string selectedBand = ((ListItem)priceBand.SelectedItem).Key;
            if (selectedBand == "BB")
                m.addBollingerBand(20, 2, 0x9999ff, unchecked((int)(0xc06666ff)));
            else if (selectedBand == "DC")
                m.addDonchianChannel(20, 0x9999ff, unchecked((int)(0xc06666ff)));
            else if (selectedBand == "Envelop")
                m.addEnvelop(20, 0.1, 0x9999ff, unchecked((int)(0xc06666ff)));

            //
            // Add volume bars to the main chart if necessary
            //
            if (volumeBars.Checked)
                m.addVolBars(indicatorHeight, 0x99ff99, 0xff9999, 0xc0c0c0);

            //
            // Add additional indicators as according to user selection.
            //
            addIndicator(m, ((ListItem)indicator2.SelectedItem).Key, indicatorHeight);
            //totalHeight += indicatorHeight;
            addIndicator(m, ((ListItem)indicator3.SelectedItem).Key, indicatorHeight);
            //totalHeight += indicatorHeight;
            addIndicator(m, ((ListItem)indicator4.SelectedItem).Key, indicatorHeight);
            totalHeight += indicatorHeight;
            totalHeight += mainHeight;


            

            
            //
            // output the chart
            //
            viewer.Chart = m;

            //
            // tooltips for the chart
            //
            viewer.ImageMap = m.getHTMLImageMap("", "", "title='" + m.getToolTipDateFormat()
                + " {value|P}'");
        }

        /// <summary>
        /// Add a moving average line to the FinanceChart object.
        /// </summary>
        /// <param name="m">The FinanceChart object to add the line to.</param>
        /// <param name="avgType">The moving average type (SMA/EMA/TMA/WMA).</param>
        /// <param name="avgPeriod">The moving average period.</param>
        /// <param name="color">The color of the line.</param>
        /// <returns>The LineLayer object representing line layer created.</returns>
        protected LineLayer addMovingAvg(FinanceChart m, string avgType, int avgPeriod, int color)
        {
            if (avgPeriod > 1)
            {
                if (avgType == "SMA")
                    return m.addSimpleMovingAvg(avgPeriod, color);
                else if (avgType == "EMA")
                    return m.addExpMovingAvg(avgPeriod, color);
                else if (avgType == "TMA")
                    return m.addTriMovingAvg(avgPeriod, color);
                else if (avgType == "WMA")
                    return m.addWeightedMovingAvg(avgPeriod, color);
            }
            return null;
        }

        /// <summary>
        /// Add an indicator chart to the FinanceChart object. In this demo example, the indicator
        /// parameters (such as the period used to compute RSI, colors of the lines, etc.) are hard
        /// coded to commonly used values. You are welcome to design a more complex user interface 
        /// to allow users to set the parameters.
        /// </summary>
        /// <param name="m">The FinanceChart object to add the line to.</param>
        /// <param name="indicator">The selected indicator.</param>
        /// <param name="height">Height of the chart in pixels</param>
        /// <returns>The XYChart object representing indicator chart.</returns>
        protected XYChart addIndicator(FinanceChart m, string indicator, int height)
        {
            if (indicator == "RSI")
                return m.addRSI(height, 14, 0x800080, 20, 0xff6666, 0x6666ff);
            else if (indicator == "StochRSI")
                return m.addStochRSI(height, 14, 0x800080, 30, 0xff6666, 0x6666ff);
            else if (indicator == "MACD")
                return m.addMACD(height, 26, 12, 9, 0xff, 0xff00ff, 0x8000);
            else if (indicator == "FStoch")
                return m.addFastStochastic(height, 14, 3, 0x6060, 0x606000);
            else if (indicator == "SStoch")
                return m.addSlowStochastic(height, 14, 3, 0x6060, 0x606000);
            else if (indicator == "ATR")
                return m.addATR(height, 14, 0x808080, 0xff);
            else if (indicator == "ADX")
                return m.addADX(height, 14, 0x8000, 0x800000, 0x80);
            else if (indicator == "DCW")
                return m.addDonchianWidth(height, 20, 0xff);
            else if (indicator == "BBW")
                return m.addBollingerWidth(height, 20, 2, 0xff);
            else if (indicator == "DPO")
                return m.addDPO(height, 20, 0xff);
            else if (indicator == "PVT")
                return m.addPVT(height, 0xff);
            else if (indicator == "Momentum")
                return m.addMomentum(height, 12, 0xff);
            else if (indicator == "Performance")
                return m.addPerformance(height, 0xff);
            else if (indicator == "ROC")
                return m.addROC(height, 12, 0xff);
            else if (indicator == "OBV")
                return m.addOBV(height, 0xff);
            else if (indicator == "AccDist")
                return m.addAccDist(height, 0xff);
            else if (indicator == "CLV")
                return m.addCLV(height, 0xff);
            else if (indicator == "WilliamR")
                return m.addWilliamR(height, 14, 0x800080, 30, 0xff6666, 0x6666ff);
            else if (indicator == "Aroon")
                return m.addAroon(height, 14, 0x339933, 0x333399);
            else if (indicator == "AroonOsc")
                return m.addAroonOsc(height, 14, 0xff);
            else if (indicator == "CCI")
                return m.addCCI(height, 20, 0x800080, 100, 0xff6666, 0x6666ff);
            else if (indicator == "EMV")
                return m.addEaseOfMovement(height, 9, 0x6060, 0x606000);
            else if (indicator == "MDX")
                return m.addMassIndex(height, 0x800080, 0xff6666, 0x6666ff);
            else if (indicator == "CVolatility")
                return m.addChaikinVolatility(height, 10, 10, 0xff);
            else if (indicator == "COscillator")
                return m.addChaikinOscillator(height, 0xff);
            else if (indicator == "CMF")
                return m.addChaikinMoneyFlow(height, 21, 0x8000);
            else if (indicator == "NVI")
                return m.addNVI(height, 255, 0xff, 0x883333);
            else if (indicator == "PVI")
                return m.addPVI(height, 255, 0xff, 0x883333);
            else if (indicator == "MFI")
                return m.addMFI(height, 14, 0x800080, 30, 0xff6666, 0x6666ff);
            else if (indicator == "PVO")
                return m.addPVO(height, 26, 12, 9, 0xff, 0xff00ff, 0x8000);
            else if (indicator == "PPO")
                return m.addPPO(height, 26, 12, 9, 0xff, 0xff00ff, 0x8000);
            else if (indicator == "UO")
                return m.addUltimateOscillator(height, 7, 14, 28, 0x800080, 20, 0xff6666, 0x6666ff);
            else if (indicator == "Vol")
                return m.addVolIndicator(height, 0x99ff99, 0xff9999, 0xc0c0c0);
            else if (indicator == "TRIX")
                return m.addTRIX(height, 12, 0xff);
            return null;
        }

        /// <summary>
        /// Creates a dummy chart to show an error message.
        /// </summary>
        /// <param name="viewer">The WinChartViewer to display the error message.</param>
        /// <param name="msg">The error message</param>
        protected void errMsg(WinChartViewer viewer, string msg)
        {
            MultiChart m = new MultiChart(400, 200);
            m.addTitle2(Chart.Center, msg, "Arial", 10).setMaxWidth(m.getWidth());
            viewer.Image = m.makeImage();
        }

        private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
        private void InitTimer()
        {
            timer.Interval = 1000;
            timer.Tick += new EventHandler(OnTimerTick);
            timer.Start();
        }

        private void OnTimerTick(object sender, EventArgs e)
        {
            DateTime curDate = DateTime.Now;
            string topLabelText = "현재시간 : ";
            topLabelText += curDate.Year.ToString() + "년";
            topLabelText += curDate.Month.ToString() + "월";
            topLabelText += curDate.Day.ToString() + "일";
            topLabelText += curDate.Hour.ToString() + "시";
            topLabelText += curDate.Minute.ToString() + "분";
            topLabelText += curDate.Second.ToString() + "초";

            topLabel.Text = topLabelText;
            if (hasFinishedInitialization)
                drawChart(optChartViewer);
        }
    }
}
